/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package model;

import java.util.ArrayList;
import java.util.Random;
import javax.swing.JOptionPane;
import model.util.pilas.StackList;

/**
 *
 * @author Gus-Gus
 */
public class AlgoritmoLaberinto {

    private static final int FILA = 15;
    private static final int COLUMNA = 15;
    
    private String solucionLaberinto = "";
    private String movimientosNecesarios = "";
    
    boolean[][] laberinto = new boolean[FILA][COLUMNA];
    boolean[][] solucionLaberintos = new boolean[FILA][COLUMNA];
    
    StackList pilaMovimientos = new StackList();
    //StackList pilaInvertida = null;
    
    ArrayList recorridos = new ArrayList();
    boolean[][] matriz = new boolean[FILA][COLUMNA];

    private boolean posicionRecorrida(Posicion pos) {
        boolean hePasado = false;
        for (int i = 0; i < recorridos.size(); i++) {
            if (pos.getI() == ((Posicion) recorridos.get(i)).getI() && pos.getJ() == ((Posicion) recorridos.get(i)).getJ()) {
                hePasado = true;
            }
        }
        return hePasado;
    }
    
    public AlgoritmoLaberinto(){
        
    }

    public AlgoritmoLaberinto(boolean lab[][]) {
        this.laberinto = lab;
    }

    /**
     * *********
     * metodo que recibe como parametros 2 pilas una que es la de entrada y una
     * la de salida e invierte los datos de la pila que tenga datos.
     *
     * @param entrada
     * @param salida
     */
    public void inviertePila(StackList entrada, StackList salida) {
        salida = new StackList();
        //while que invierte los datos de la pila de entrada
        while (!entrada.isEmpty()) {
            salida.push(entrada.pop());
        }

        //while que imprime la pila de la salida ya invertida.
        while (!salida.isEmpty()) {
            System.out.println(salida.top());
        }

    }

    public boolean[][] getLaberinto() {
        return laberinto;
    }

    public boolean[][] getMatriz() {
        return matriz;
    }

    public String getMovimientosNecesarios() {
        return movimientosNecesarios;
    }

    public void camino() throws Exception {
        boolean exitoFinal = false;
        boolean existeSolucion = true;
        
        int i = 1;
        int j = 1;
        
        
        try{

        recorridos.clear();
        pilaMovimientos = new StackList();
        solucionLaberinto = "";
        movimientosNecesarios = "";


        while (!pilaMovimientos.isEmpty() || exitoFinal != true) {
            recorridos.add(new Posicion(i, j));
           

            if (laberinto[i][j + 1] == true && !this.posicionRecorrida(new Posicion(i, j + 1))) {
                j++;
                pilaMovimientos.push(new Movimiento(i, j, "E"));
                this.movimientosNecesarios = movimientosNecesarios + "Recorrer [" + i + "][" + j + "] hacia E\n";

            } else {
                if (laberinto[i + 1][j + 1] == true && !this.posicionRecorrida(new Posicion(i + 1, j + 1))) {
                    i++;
                    j++;
                    pilaMovimientos.push(new Movimiento(i, j, "SE"));
                    this.movimientosNecesarios = movimientosNecesarios + "Recorrer [" + i + "][" + j + "] hacia SE\n";

                } else {

                    if (laberinto[i + 1][j] == true && !this.posicionRecorrida(new Posicion(i + 1, j))) {
                        i++;
                        pilaMovimientos.push(new Movimiento(i, j, "S"));
                        this.movimientosNecesarios = movimientosNecesarios + "Recorrer [" + i + "][" + j + "] hacia S\n";

                    } else {
                        //Si estamos en el inicio del laberinto y estan bloqueados E, SE, S e intentamos checar SE pero al checar lanza excepcion
                        //finalizamos el juego porque aun seguimos en el inicio del laberinto
                        if (j - 1 < 0) {
                            Movimiento mov = (Movimiento) pilaMovimientos.pop();
                            this.movimientosNecesarios += "fueraPila:[" + mov.toString();

                        }

                        if (laberinto[i + 1][j - 1] == true && !this.posicionRecorrida(new Posicion(i + 1, j - 1))) {
                            i++;
                            j--;
                            pilaMovimientos.push(new Movimiento(i, j, "SO"));
                            this.movimientosNecesarios = movimientosNecesarios + "Recorrer [" + i + "][" + j + "] hacia SO\n";

                        } else {

                            if (laberinto[i][j - 1] == true && !this.posicionRecorrida(new Posicion(i, j - 1))) {
                                j--;
                                pilaMovimientos.push(new Movimiento(i, j, "O"));
                                this.movimientosNecesarios = movimientosNecesarios + "pila.push[" + i + "][" + j + "] en direccion O\n";

                            } else {

                                if (laberinto[i - 1][j - 1] == true && !this.posicionRecorrida(new Posicion(i - 1, j - 1))) {
                                    i--;
                                    j--;
                                    pilaMovimientos.push(new Movimiento(i, j, "NO"));
                                    this.movimientosNecesarios = movimientosNecesarios + "pila.push[" + i + "][" + j + "] en direccion NO\n";
                                } else {

                                    if (laberinto[i - 1][j] == true && !this.posicionRecorrida(new Posicion(i - 1, j))) {
                                        i--;
                                        pilaMovimientos.push(new Movimiento(i, j, "N"));
                                        this.movimientosNecesarios = movimientosNecesarios + "pila.push[" + i + "][" + j + "] en direccion N\n";

                                    } else {

                                        if (laberinto[i - 1][j + 1] == true && !this.posicionRecorrida(new Posicion(i - 1, j + 1))) {
                                            i--;
                                            j++;
                                            pilaMovimientos.push(new Movimiento(i, j, "NE"));
                                            this.movimientosNecesarios = movimientosNecesarios + "pila.push[" + i + "][" + j + "] en direccion NE\n";

                                        } else {

                                            this.laberinto[i][j] = false;//Sino tiene opciones de movimiento, se vuelve falso
                                            Movimiento movimiento = (Movimiento) pilaMovimientos.pop();
                                            this.movimientosNecesarios = movimientosNecesarios + "pila.pop:" + movimiento.toString() + "\n";

                                            //System.out.println("en la lista la ultima posicion es ["+((Posicion)lista.get(lista.size()-1)).getI()+"]["+((Posicion)lista.get(lista.size()-1)).getI()+"]");
                                            recorridos.remove(recorridos.size() - 1);
                                            recorridos.remove(recorridos.size() - 1);

//Para saber si estaba en inicio o salida
                                            i = movimiento.getI();
                                            j = movimiento.getJ();
                                            if (i == 1 && j == 0) {
                                                exitoFinal = true;
                                                Movimiento mov = (Movimiento) pilaMovimientos.pop();
                                                this.movimientosNecesarios += "Sacamos de pila:[" + mov.toString();
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (i == 13 && j == 13) {
                exitoFinal = true;
                
            }


        }
        }catch (Exception e){}
        
        if (!pilaMovimientos.isEmpty()) {
            System.out.println("Solucionado");
            while (!pilaMovimientos.isEmpty()) {
                Movimiento m = (Movimiento) pilaMovimientos.pop();
                solucionLaberintos[m.getI()][m.getJ()] = true;
                this.solucionLaberinto = "fuera: " + m.toString() + "\n" + solucionLaberinto;
                //System.out.println(solucionLaberinto);

            }
                            JOptionPane.showMessageDialog(null, solucionLaberinto);
        } else {
                            JOptionPane.showMessageDialog(null, "No tiene solucion");
        }
    }
    
          

    public static void main(String[] args) throws Exception {
        boolean[][] laberintoPrueba = new boolean[FILA][COLUMNA];
        Random r = new Random();
        
        for (int i = 0; i < FILA; i++) {
            for (int j = 0; j < COLUMNA; j++) {
                if (i == 0 || i == FILA || j == 0 || j == COLUMNA) {
                    laberintoPrueba[i][j] = false;
                } else {
                    laberintoPrueba[i][j] = r.nextBoolean();
                }

            }
        }
        
        Laberinto labo = new Laberinto();
       
        AlgoritmoLaberinto laberinto = new AlgoritmoLaberinto(laberintoPrueba);
        
        laberinto.camino();
    }
}